package com.alan.android.sqlite;

import static com.alan.android.sqlite.constant.Constants.DB_TAG;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import androidx.annotation.NonNull;

import com.alan.android.sqlite.reflect.ObjectFactory;
import com.alan.android.sqlite.table.Table;
import com.alan.android.sqlite.table.TableFactory;
import com.alan.android.sqlite.table.TableHelper;

import java.util.ArrayList;
import java.util.List;

public class AndroidSqlite implements IDatatabseOpertion {

    private String path;
    private Context context;

    private SQLiteDatabase database;

    public AndroidSqlite(@NonNull Context context, String path) {
        this.context = context;
        this.path = path;

        try {
            database = SQLiteDatabase.openDatabase(path, null, 0);
        } catch (Throwable e) {
            Log.e(DB_TAG, Log.getStackTraceString(e));
        }
    }

    public AndroidSqlite(SQLiteDatabase database) {
        this.database = database;
    }

    boolean isValid() {
        return database != null;
    }

    @Override
    public <T> T query(String sql, Class<T> clazz) {
        if (null == database) {
            return null;
        }
        try (Cursor cursor = database.rawQuery(sql, null)) {
            return getItem(clazz, cursor);
        }
    }

    @Override
    public <T> List<T> queryList(String sql, Class<T> clazz) {
        if (null == database) {
            return new ArrayList<>();
        }
        try (Cursor cursor = database.rawQuery(sql, null)) {
            return getList(clazz, cursor);
        }
    }

    @Override
    public boolean insert(Object o) {
        if (null == database || o == null) {
            Log.w(DB_TAG, "insert database is null or object is null!");
            return false;
        }
        Table table = TableFactory.getTable(o.getClass());
        ContentValues contentValues = TableHelper.getContentValues(o,table);
        return database.insert(table.getTableName(), null, contentValues)>0;
    }

    @Override
    public boolean replace(Object o) {
        if (null == database || o == null) {
            Log.w(DB_TAG, "replace database is null or object is null!");
            return false;
        }
        Table table = TableFactory.getTable(o.getClass());
        ContentValues contentValues = TableHelper.getContentValues(o,table);
        return database.replace(table.getTableName(), null, contentValues)>0;
    }

    @Override
    public boolean delete(Object o) {
        if (null == database ||null == o) {
            Log.w(DB_TAG, "delete database is null or object is null!");
            return false;
        }
        Table table = TableFactory.getTable(o.getClass());
        StringBuilder stringBuilder = new StringBuilder();
        String[] strings = TableHelper.whereArgs(o, table,stringBuilder);
        int delete = database.delete(table.getTableName(), stringBuilder.toString(), strings);
        Log.w(DB_TAG,"delete result:"+delete);
        return delete>0;
    }

    @Override
    public void execute(String sql) {
        if(null==database){
            return;
        }
        database.execSQL(sql);
    }


    private <T> T getItem(Class<T> tClass, Cursor cursor) {
        ObjectFactory<T> factory = new ObjectFactory<>(tClass);
        Table table = TableFactory.getTable(tClass);
        try {
            if (null != cursor && cursor.getCount() > 0 && cursor.moveToFirst()) {
                return TableHelper.getModelByCursor(table, cursor, factory);
            }
            return null;
        } catch (Exception e) {
            Log.e(DB_TAG, Log.getStackTraceString(e));
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return null;
    }

    private <T> List<T> getList(Class<T> tClass, Cursor cursor) {
        ObjectFactory<T> factory = new ObjectFactory<>(tClass);
        Table table = TableFactory.getTable(tClass);
        List<T> list = new ArrayList<>();
        try {
            while (null != cursor && cursor.getCount() > 0 && cursor.moveToNext()) {
                T t = TableHelper.getModelByCursor(table, cursor, factory);
                list.add(t);
            }
        } catch (Exception e) {
            Log.e(DB_TAG, Log.getStackTraceString(e));
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return list;
    }

    public void release() {
        if (null != database) {
            database.close();
        }
    }

}
